
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include "bsp-generator.h"
#include "map.h"

Map::Map(Mersenne_Twister *mt, std::string filename)
{
	RNG = mt;
	loadMap(filename);
}

Map::~Map()
{
	MAP.clear();
}
/*
bool Map::isBlocked(Object *viewer, Object *viewed)
{
	int dx, dy, absx, absy, sx, sy;
	dx = viewed->x() - viewer->x();
	dy = viewed->y() - viewer->y();
	absx = abs(dx);
	absy = abs(dy);
	sx = (dx >= 0) ? 1 : -1;
	sy = (dy >= 0) ? 1 : -1;
	return true;
}
*/
bool Map::isBlocked(int x, int y)
{
	Terrain *t = (Terrain *) MAP[y][x]->head()->object();
	if (t->isPassable())
		return true;
	else
		return false;
}	
	
bool Map::isEmpty(int x, int y)
{
	if (MAP[y][x]->size() < 2)
		return true;
	else
		return false;
}

char Map::display(int x, int y)
{
	return MAP[y][x]->tail()->object()->symbol();
}

int Map::height()
{
	return HEIGHT;
}

int Map::level()
{
	return LEVEL;
}

int Map::width()
{
	return WIDTH;
}

Object *Map::isAt(int x, int y)
{
	return MAP[y][x]->head()->object();
}

void Map::add(int x, int y, Object *object)
{
	MAP[y][x]->add(object);
}

// This function updates the screen on any objects that may have changed position
void Map::refresh()
{
	Object *object;
	for (int i=0; i<HEIGHT; i++)
	{
		for (int j=0; j<WIDTH; j++)
		{
			for (int k=1; k<MAP[i][j]->size(); k++) // k is initialized to 1 since the head is always a terrain object.
			{
				object = MAP[i][j]->pop();
				MAP[object->y()][object->x()]->push(object);
/*				object = MAP[i][j]->isAt(k);
				if ((object->x() != j) || (object->y() != i))	// if the object has moved
				{
					MAP[i][j]->remove(object);
					MAP[object->y()][object->x()]->add(object);
				}
*/			}
		}	
	}

}

// This function sets the position to the desired tile.
void Map::set(Object *object)
{
	MAP[object->y()][object->x()]->add(object);
}

// This function loads the map data from a .map file.
void Map::loadMap(std::string filename)
{
	bool hasdownstairs, hasupstairs;
	int i, j;
	char c;
	std::string line;
	std::ifstream myfile(filename.c_str());
	if (myfile.is_open())
	{
		getline(myfile, line);
		std::stringstream ss;
		ss << line;
		ss >> WIDTH >> HEIGHT >> LEVEL;			// The beginning of every .map file should be the width, height and level number.
		std::cerr << "Width: " << WIDTH << " Height: " << HEIGHT << std::endl;

		for (i=0; i<HEIGHT; i++)
		{
			std::vector< Double_Linked_List * > row;
			for (j=0; j<WIDTH; j++)
			{
				row.push_back(new Double_Linked_List());
			}
			MAP.push_back(row);
		}
		
		// Read in the rest of the file.
		getline(myfile, line);
		ss << line;
		if (line == "MAP")				// The map is already defined.
		{
			for (i=0; i<HEIGHT; i++)
			{
				getline(myfile, line);
				for (j=0; j<WIDTH; j++)
				{
					c = line[j];
					if (c == '.')
						MAP[i][j]->add(new Terrain("floor", c, i, j, 0, true, false, 10));
					else if (c == '#')
						MAP[i][j]->add(new Terrain("wall", c, i, j, 0, false, false, 0));
					else if (c == '+')
						MAP[i][j]->add(new Terrain("door", c, i, j, 0, true, false, 20));
					else if (c == '>')
						MAP[i][j]->add(new Terrain("downstairs", c, i, j, 0, true, false, 20));
					else if (c == '<')
						MAP[i][j]->add(new Terrain("upstairs", c, i, j, 0, true, false, 20));
					else	// This is for undefined characters
						MAP[i][j]->add(new Terrain("nothing", ' ', i, j, 0, true, false, 0));
				}
			}
		}
		else if (line == "RANDOM")			// The map must be procedurally generated.
		{
			getline(myfile, line);
			ss << line;
			ss >> hasdownstairs >> hasupstairs;
			
			BSP_Generator *bsp = new BSP_Generator(RNG, WIDTH, HEIGHT, hasdownstairs, hasupstairs);
			
			for (i=0; i<HEIGHT; i++)
			{
				for (j=0; j<WIDTH; j++)
				{
					c = bsp->isAt(j, i);
					if (c == '.')
						MAP[i][j]->add(new Terrain("floor", '.', i, j, 0, true, false, 10));
					else if (c == '#')
						MAP[i][j]->add(new Terrain("wall", '#', i, j, 0, false, false, 0));
					else if (c == '+')
						MAP[i][j]->add(new Terrain("door", c, i, j, 0, true, false, 20));
					else if (c == '>')
						MAP[i][j]->add(new Terrain("downstairs", c, i, j, 0, true, false, 20));
					else if (c == '<')
						MAP[i][j]->add(new Terrain("upstairs", c, i, j, 0, true, false, 20));
					else	// This is for undefined characters
						MAP[i][j]->add(new Terrain("nothing", ' ', i, j, 0, true, false, 0));
				}
			}
			delete bsp;
		}
		else
		{
			std::cerr << "Invalid file: " << filename << "!" << std::endl;
			myfile.close();
			return;
		}
	}
	else
		std::cerr << "Unable to open file " << filename << "!" << std::endl;
	myfile.close();
//	printMap();
}

// DEBUG ONLY
void Map::printMap()
{
	for (int i=0; i<HEIGHT; i++)
	{
		for (int j=0; j<HEIGHT; j++)
		{
			for (int k=0; k<MAP[i][j]->size(); k++)
			{
				std::cerr << MAP[i][j]->isAt(k)->symbol();
			}
		}
		std::cerr << std::endl;
	}
}

